/** Java 1.3 AST Recognizer Grammar
 *
 * Author: (see java.g preamble)
 *
 * This grammar is in the PUBLIC DOMAIN
 */
class MethodExtracter extends TreeParser;

options {
	importVocab = Java;
}

{
    public void setCurrentInfo(ClassData cinfo) {
        _currentCInfo = cinfo;
    }

    public void setSkipMC(AST skipMC) {
        _skipMC = skipMC;
    }

    public void setSkipMCTable(HashMap skipMCTable) {
        _skipMCTable = skipMCTable;
    } 

    public void setFlowGraph(FlowGraph fg) {
        _flowGraph = fg;
    }
 
    public void setFlowGraphNode(FlowGraphNode node) {
        _node = node;
    }
    
    public void setStatementIndex(int index) {
        _statementIndex = index;
    }

    public void resetBBSplit() {
         _bbSplit = false;
    }
    
    public boolean getBBSplit() {
        return _bbSplit;
    }
    
    public void setVarIdentifiers(HashMap vid) {
        _varIdentifiers = vid;
    }

    private FlowGraphNode _node;
    private int _statementIndex;
    
    private HashMap _varIdentifiers;

    // Indica que um BB foi divido. Isso so pode ser feito uma vez, mesmo que o statement tenha
    // mais de um metodo a ser removido
    private boolean _bbSplit;
    

    private FlowGraph _flowGraph;
    private int _uniqueCount = 0;
    
    // Impede que os MC de assign e vardef do MethodCallNode sejam processados.
    private AST _skipMC = null;
    private HashMap _skipMCTable;
    
    private ClassData _currentCInfo;
    
    private boolean _forCondition = false;
    private boolean _forIterator = false;
}

statement: stat

	|   #(CTOR_CALL elist)
			      
	|  SUPER_CTOR_CALL // ( elist | primaryExpression elist ) )
	
	// Cloquei esta regra novamente aqui, pois os MethodCallNode sao criados a partir do no
	// METHOD_CALL, e nao EXPR	
	| #(METHOD_CALL primaryExpression elist) 

        // Os proximos tres casos sao para o processamento de um ForBeginNode
        | #(FOR_INIT (variableDef | elist)?)
	
	| #(FOR_CONDITION 
	   
	     { _forCondition = true; }
	   
	     (expression)?
	     
	     { _forCondition = false; }
	   
	   )
	
	| #(FOR_ITERATOR 
	     
	     { _forIterator = true; }
	     
	     (elist)?
	     
	     { _forIterator = false; }
	     
	   )
	
	;

stat:	//typeDefinition

        	variableDef

	|	expression

	|	#(LABELED_STAT IDENT stat)

/*	|	#("if" expression stat (stat)? )
	|	#(	"for"
			#(FOR_INIT (variableDef | elist)?)
			#(FOR_CONDITION (expression)?)
			#(FOR_ITERATOR (elist)?)
			stat
		)
	|	#("while" expression stat)
	|	#("do" stat expression)
	|	#("break" (IDENT)? )
	|	#("continue" (IDENT)? )
	|	#("return" (expression)? )
	|	#("switch" expression (caseGroup)*)
	|	#("throw" expression)
	|	#("synchronized" expression stat)
	|	tryBlock */

	|	slist // nested SLIST
	|	EMPTY_STAT
	;

typeSpec
	:	#(TYPE typeSpecArray)
	;

type:	identifier
	|	builtInType
	;

typeSpecArray
	:	#( ARRAY_DECLARATOR typeSpecArray )
	|	type
	;

builtInType
    :   "void"
    |   "boolean"
    |   "byte"
    |   "char"
    |   "short"
    |   "int"
    |   "float"
    |   "long"
    |   "double"
    ;

modifiers
	:	#( MODIFIERS (modifier)* )
	;

modifier
    :   "private"
    |   "public"
    |   "protected"
    |   "static"
    |   "transient"
    |   "final"
    |   "abstract"
    |   "native"
    |   "threadsafe"
    |   "synchronized"
    |   "const"
    |   "volatile"
	|	"strictfp"
    ;

parameterDef
	:	#(PARAMETER_DEF modifiers typeSpec IDENT )
	;

variableDef
	:	#(VARIABLE_DEF modifiers typeSpec variableDeclarator varInitializer)
	;

variableDeclarator
	:	IDENT
	|	LBRACK variableDeclarator
	;

varInitializer
	:	#(ASSIGN initializer)
	|
	;

initializer
	:	expression
	|	arrayInitializer
	;

arrayInitializer
	:	#(ARRAY_INIT (initializer)*)
	;


identifier   
	:	IDENT 
	|	#( DOT identifier IDENT )
	;

identifierStar
	:	IDENT
	|	#( DOT identifier (STAR|IDENT) )
	;

slist
	:	#( SLIST (stat)* )
	;

caseGroup
	:	#(CASE_GROUP (#("case" expression) | "default")+ slist)
	;

tryBlock
	:	#( "try" slist (handler)* (#("finally" slist))? )
	;

handler
	:	#( "catch" parameterDef slist )
	;

elist
	:	#( ELIST (expression)* )
	;

expression
	:	#(EXPR expr)
	;

expr:	#(QUESTION expr expr expr)	
	|	#(ASSIGN expr expr)
	|	#(PLUS_ASSIGN expr expr)
	|	#(MINUS_ASSIGN expr expr)
	|	#(STAR_ASSIGN expr expr)
	|	#(DIV_ASSIGN expr expr)
	|	#(MOD_ASSIGN expr expr)
	|	#(SR_ASSIGN expr expr)
	|	#(BSR_ASSIGN expr expr)
	|	#(SL_ASSIGN expr expr)
	|	#(BAND_ASSIGN expr expr)
	|	#(BXOR_ASSIGN expr expr)
	|	#(BOR_ASSIGN expr expr)
	|	#(LOR expr expr)
	|	#(LAND expr expr)
	|	#(BOR expr expr)
	|	#(BXOR expr expr)
	|	#(BAND expr expr)
	|	#(NOT_EQUAL expr expr)
	|	#(EQUAL expr expr)
	|	#(LT expr expr)
	|	#(GT expr expr)
	|	#(LE expr expr)
	|	#(GE expr expr)
	|	#(SL expr expr)
	|	#(SR expr expr)
	|	#(BSR expr expr)
	|	#(PLUS expr expr)
	|	#(MINUS expr expr)
	|	#(DIV expr expr)
	|	#(MOD expr expr)
	|	#(STAR expr expr)
	|	#(INC expr)
	|	#(DEC expr)
	|	#(POST_INC expr)
	|	#(POST_DEC expr)
	|	#(BNOT expr)
	|	#(LNOT expr)
	|	#("instanceof" expr expr)
	|	#(UNARY_MINUS expr)
	|	#(UNARY_PLUS expr)
	|	primaryExpression
	;

primaryExpression
    :   IDENT
    |   #(	DOT
			(	expr
				(	IDENT
				|	arrayIndex
				|	"this"
				|	"class"
				|	#( "new" IDENT elist )
				|   "super"
				)
			|	#(ARRAY_DECLARATOR typeSpecArray)
			|	builtInType ("class")?
			)
		)

	|	arrayIndex
	

	|	#(n1:METHOD_CALL n2:primaryExpression n3:elist) {

                    if(n1 != _skipMC) {
		        if(_node.getType() == FlowGraphNode.BASIC_BLOCK) {
			    if(_statementIndex != 0 && !_bbSplit) {
		                _bbSplit = true;
			    }
			}

			if(_forCondition || _node.getType() == FlowGraphNode.WHILE_BEGIN) {
			    ForConditionMethodExtraction trans = 
			        new ForConditionMethodExtraction(_flowGraph);
                            LinkedList args = new LinkedList();
			    args.add(n1);
			    args.add(n2);
			    args.add(n3);
			    args.add(_node);
			    args.add(_skipMCTable);

			    trans.transform(args);
			}
			else
		        if(_forIterator) {
			    ForIteratorExtraction trans = new ForIteratorExtraction(_flowGraph);
			    trans.transform(n1, n2, n3, _node, _skipMCTable);
			}
			else {
			    MethodExtraction trans = new MethodExtraction(_flowGraph);
                            LinkedList args = new LinkedList();
			    args.add(n1);
			    args.add(n2);
			    args.add(n3);
			    args.add(_node);
			    args.add(_skipMCTable);
			    args.add(new Boolean(_bbSplit));
			    args.add(new Integer(_statementIndex));

			    trans.transform(args);
			}
		    }
	        }

	|	#(TYPECAST typeSpec expr)
	
	|   newExpression
	
	|   constant
	
    |   "super"
    |   "true"
    |   "false"
    |   "this"
    |   "null"
	|	typeSpec // type name used with instanceof
	;

ctorCall
	:	#( CTOR_CALL elist )
	|	#( SUPER_CTOR_CALL
			(	elist
			|	primaryExpression elist
			)
		 )
	;

arrayIndex
	:	#(INDEX_OP primaryExpression expression)
	;

constant
    :   NUM_INT
    |   CHAR_LITERAL
    |   STRING_LITERAL
    |   NUM_FLOAT
    |   NUM_DOUBLE
    |   NUM_LONG
    ;

newExpression   
	:	#(	n1:"new" n2:type
	
			(	
			        newArrayDeclarator 

				(arrayInitializer)?
			
			|	elist 
			        (n3:OBJBLOCK {				

                                     if(_node.getType() == FlowGraphNode.BASIC_BLOCK) {
			                 if(_statementIndex != 0 && !_bbSplit) {
		                             _bbSplit = true;
			                 }
		  	             }
				     
				     AnonymousClassExtraction trans = 
				         new AnonymousClassExtraction(_flowGraph);

				     trans.transform(n1, n2, n3, _node, _bbSplit, _statementIndex,
				         _currentCInfo);
				
				}  )?)

			// (objBlock)? )
		)
	;
	
newArrayDeclarator
	:	#( ARRAY_DECLARATOR (newArrayDeclarator)? (expression)? )
	;
